#include "Bucket.h"


Bucket::Bucket(unsigned int tamaniobucket, Bloque * bloque){
		this->bloque =bloque;
		this->cantBytesLibres=bloque->obtenerBytesLibres();
		unsigned int cantidadregistros=bloque->cantidadRegistros();

		//el primer registro de mi bloque es el td
		Registro * registro=bloque->obtenerRegistro(1);
		tamDispersionBucket=Util::stringToInt(registro->buffer);

		//armo el vector de Keys
		for(unsigned int x=1; x<cantidadregistros; x++) {
			Registro *registro = bloque->obtenerRegistro(x+1);
			Key* key = new Key (obtenerClave(registro->buffer), obtenerValor(registro->buffer));
			vectorKeys.push_back(key);
	    }
}


Bucket::~Bucket(){
}


bool Bucket::existe (Key key){
	bool existe=false;
	for(unsigned int x=0; x<vectorKeys.size(); x++) {
		Key* keyVector = vectorKeys[x];
		if (keyVector->obtenerClave()==key.obtenerClave()){
			existe=true;
		}
    }
	return existe;
}

string Bucket::buscar(Key key){
	string valor="";
	if (existe (key)){
		for(unsigned int x=0; x<vectorKeys.size(); x++) {
			Key* keyVector = vectorKeys[x];
			if (keyVector->obtenerClave()==key.obtenerClave()){
				valor= keyVector->obtenerValor();
				return valor;
			}
		} return valor;
	} else return valor;
}

bool Bucket::desborda (Key key){
	bool desborda=true;
	if (bloque->obtenerBytesLibres()>(key.obtenerRegistro()->buffer).length()){
		desborda=false;
	}
	return desborda;
}


bool Bucket::insertar (Key key, unsigned int tamtabla){

	//Si la clave ya existe no hago nada y devuelvo true
	if ( !(this->existe(key))) {

		//Si tengo lugar libre en el bloque inserto
		if (bloque->obtenerBytesLibres()>=(key.obtenerRegistro()->buffer).length()){
			Key * keyIns= new Key (key.obtenerClave(), key.obtenerValor());
			vectorKeys.push_back(keyIns);
			unsigned int tamaniobloque=bloque->tamBloque;
			tamDispersionBucket=tamtabla;
			bloque->~Bloque();
			this->bloque=new Bloque(tamaniobloque);

			//agrego el tamanio de dispersion que es el primer registro del bloque
			Registro registrotd = Registro(Util::stringToCharAst(Util::uIntToString(tamDispersionBucket)));
			this->bloque->agregarRegistro(registrotd);

			for(unsigned int x=0; x<vectorKeys.size(); x++) {
				Key* keyVector = vectorKeys[x];
				this->bloque->agregarRegistro(*keyVector->obtenerRegistro());
			}
			return true;

		} else return false;
	} else return false;

}


bool Bucket::borrar (Key key, unsigned int tamtabla){
	if ( (this->existe(key))) {
		unsigned int tamaniobloque=bloque->tamBloque;

		for(unsigned int x=0; x<vectorKeys.size(); x++) {
				Key* keyVector=vectorKeys[x];
				if(keyVector->obtenerClave()==key.obtenerClave()){
					vectorKeys.erase(vectorKeys.begin() + x);
				}
			}
			tamDispersionBucket=tamtabla;
			bloque->~Bloque();
			this->bloque=new Bloque(tamaniobloque);

			//agrego el tamanio de dispersion que es el primer registro del bloque
			Registro registrotd = Registro(Util::stringToCharAst(Util::uIntToString(tamDispersionBucket)));
			this->bloque->agregarRegistro(registrotd);

			for(unsigned int x=0; x<vectorKeys.size(); x++) {
				Key* keyVector = vectorKeys[x];
				this->bloque->agregarRegistro(*keyVector->obtenerRegistro());
			}
		} else return false;
	return true;
}


bool Bucket::modificar (Key key, unsigned int tamtabla){
	if ( (this->existe(key))) {
		unsigned int tamaniobloque=bloque->tamBloque;

		Key * keyIns= new Key (key.obtenerClave(), key.obtenerValor());
		Key* keyVector;
		vector<Key*>tempVectorKeys;
		unsigned int posmodif=0;
		for(unsigned int x=0;x<vectorKeys.size(); x++) {
			keyVector = vectorKeys[x];
			int clave1=(keyVector->obtenerClave());
			int clave2=key.obtenerClave();

			if(clave1 == clave2 ){
				posmodif=x;
			}
		};
			vectorKeys[posmodif]=keyIns;
			tamDispersionBucket=tamtabla;
			bloque->~Bloque();
			this->bloque=new Bloque(tamaniobloque);

			//agrego el tamanio de dispersion que es el primer registro del bloque
			Registro registrotd = Registro(Util::stringToCharAst(Util::uIntToString(tamDispersionBucket)));
			this->bloque->agregarRegistro(registrotd);

			for(unsigned int x=0; x<vectorKeys.size(); x++) {
				Key* keyVector = vectorKeys[x];

				this->bloque->agregarRegistro(*keyVector->obtenerRegistro());
			}
		} else return false;
	return true;
}


unsigned int Bucket::obtenerCantidadBytesLibres(){
	return this->bloque->obtenerBytesLibres();
}


int Bucket::obtenerTamanioDispersion(){
	Registro * registro=this->bloque->obtenerRegistro(1);
	return Util::stringToInt(registro->buffer);
}

void Bucket::modificarTamanioDispersion(int tamanioDispersion){
	tamDispersionBucket=tamanioDispersion;
	unsigned int tamanioBloque=bloque->tamBloque;
	bloque->~Bloque();
	this->bloque=new Bloque(tamanioBloque);

	//agrego el tamanio de dispersion que es el primer registro del bloque
	Registro registrotd = Registro(Util::stringToCharAst(Util::uIntToString(tamDispersionBucket)));
	this->bloque->agregarRegistro(registrotd);

	for(unsigned int x=0; x<vectorKeys.size(); x++) {
		Key* keyVector = vectorKeys[x];
		this->bloque->agregarRegistro(*keyVector->obtenerRegistro());
	}

}

Bloque* Bucket::obtenerBloque(){
	return this->bloque;
}


int Bucket::obtenerClave(string buffer){
	unsigned int contadorPos = 0;
	int i = 0;
	char c = buffer[i];
	int finCadena = buffer.size();
	while((i <= finCadena) and (c != '|')){
		contadorPos++;
		i++;
		c = buffer[i];
    }
	string cadenaRet = buffer.substr(0, contadorPos);
	return Util::stringToInt(cadenaRet);
}


std::string Bucket::obtenerValor(string buffer){
	unsigned int contadorPos = 0;
	contadorPos=buffer.find('|');
	string cadenaRet =buffer.substr(contadorPos+1);
	return cadenaRet;
}


vector<Key*>  Bucket::obtenerVector(){
	return vectorKeys;
}

int Bucket::obtenerCantidadKeys(){
	return this->vectorKeys.size();
}
